#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
 Jexjex
 a minimal stack webframework
 Copyright Jan-Karel Visser - all rights are reserved
 Licensed under the LGPLv3 (http://www.gnu.org/licenses/lgpl.html)

 This program is distributed in the hope that it will be useful, but
 WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

"""

import os
import sys
import hashlib
import datetime
from jexjex.template import TemplateParser
from jexjex.helpers import echo, serve_file, literal_evil, parse_qsl, \
                  timeparts, fetch_url, cookiedate, extension, Tools, tag
from jexjex.dal import BaseAdapter, DAL, Field
from jexjex.vorm import vorm_validate, Vorm
from wsgiref import simple_server
import traceback

func = False
app = False

__autor__ = "Jan-Karel Visser"
__version__ = '0.1'
__license__ = 'LGPLv3'

py = sys.version_info
py3 = py >= (3, 0, 0)
py25 = py <= (2, 5, 0)

if py25:
    def bytes(e):
        return str(e)
if not py3:
    #not yet complete, rewritten
    from jexjex.mail import Mail


class Storage(dict):
    """
    Eventually this should replace class Storage but causes memory leak
    because of http://bugs.python.org/issue1469629
    """
    __slots__ = ()
    __setattr__ = dict.__setitem__
    __delattr__ = dict.__delitem__
    __getitem__ = dict.get
    __getattr__ = dict.get
    __repr__ = lambda self: '<Storage %s>' % dict.__repr__(self)
    __getstate__ = lambda self: None
    __copy__ = lambda self: Storage(self)


class Request(Storage):

    def __init__(self):
        Storage.__init__(self)
        self.wsgi = Storage()
        self.env = Storage()
        self.post = Storage()
        self.vars = Storage()
        self.args = Storage()
        self.now = datetime.datetime.now()
        self.utcnow = datetime.datetime.utcnow()

    def arg(self, req=0):
        return self.args[req]


class Memory(Storage):
    """
    Holds stuff in memory

    """

    def __init__(self):
        Storage.__init__(self)
        self.settings = Storage()
        self.data = Storage()
        self.cache = Storage()
        self.view = Storage()
        self.now = datetime.datetime.now()
        self.utcnow = datetime.datetime.utcnow()
        self.language = Storage()
        self.cdn_string = None
        self.gae_cdn_string = None
        self.appfolder = 'application'
        self.hits = 0
        self.folder = ''
        self.secure = 'jexjex'

    def clear_mem(self):
        tot = len(self.cache) + len(self.view)
        for key in self.cache:
                self.cache[key] = False
        for key in self.view:
                self.view[key] = False
        return tot

    def load_languages(self, folder='languages'):
        #scan language dir
        #fetch files
        #build strings
        for root, dirs, files in os.walk(self.folder + '/' + self.appfolder \
                                                               + '/' + folder):
            for taal in files:
                if taal.endswith('.lang') and not taal.startswith('__'):
                    try:
                        d = {}
                        c = taal.split('.lang')[0]
                        #print taal
                        b = self.folder + '/' + self.appfolder + '/languages/'\
                                                                         + taal
                        waarde = serve_file(b)
                        opt = literal_evil(waarde)
                        for k, v in opt.items():
                            v = v.decode('string-escape')
                            v = v.decode('utf8')
                            d[hash(k)] = v
                        self.language[c] = d
                    except:
                        pass

    def config(self, waarde):
        opt = literal_evil(waarde)
        for k, v in opt.items():
            if k == 'cdn_string':
                self.cdn_string = v
            elif k == 'gae_cdn_string':
                self.gae_cdn_string = v
            elif k == 'app_folder':
                self.appfolder = v
            elif k == 'secure':
                self.secure = v
            else:
                self.settings[k] = v
        self.load_languages()


class Jexjex:

    def __init__(self, environ=False, memory=False):
        #we need some values :)
        if environ and memory:
            self.request = Request()
            self.memory = memory
            self.memory.hits = self.memory.hits + 1
            self.headers = False
            self.post_vars = False
            self.query = False
            self.db = False
            self.mail = False
            self.auth = False
            self.post = False
            self.loggedin = False
            self.isadmin = False
            self.status = '200 ok'
            self.field = False
            self.route = False
            self.javascript_inc = []
            self.javascript_file = []
            self.css_inc = []
            self.css_file = []
            self.tools = False
            self.http = False
            self.html = Storage()
            self.data = Storage()
            self.build_request(environ)

    def get_headers(self, environ):
        headers = {}
        for k in environ:
                if k.startswith('HTTP_'):
                    e = k[5:].replace('_', '-').title()
                    headers[e] = environ[k]
        headers['REMOTE_ADDR'] = environ.get('REMOTE_ADDR', '')
        headers['SERVER_NAME'] = environ.get('SERVER_NAME', '')
        headers['REMOTE_HOST'] = environ.get('REMOTE_HOST', '')
        #for detecting appengine
        headers['APPENGINE_RUNTIME'] = environ.get('APPENGINE_RUNTIME', '')
        headers['PATH_INFO'] = environ.get('PATH_INFO', '')
        return headers

    def T(self, woord=False, waarden=False):
        if woord:
            return self.translate(woord, waarden)

    def database(self, cdn=False):
        #init a connection with a database
        if not self.db and not cdn and not hasattr(self.db, '_tables'):
            self.field = Field
            if not self.request.env.get('APPENGINE_RUNTIME', False):
                self.db = DAL(cdn or self.memory.cdn_string, \
        folder=self.memory.folder + '/' + self.memory.appfolder + '/database')
                self.gae = False
            else:
                self.db = DAL(self.memory.gae_cdn_string)
                self.gae = True
        else:
            return DAL(cdn or self.memory.cdn_string, \
                       folder=self.memory.folder + '/' + self.memory.appfolder\
                       + '/databases', migrate=False)

    def model(self, name=False, path='models', cdn=False, blanc_env=False, \
                                                                   func=False):
        if not hasattr(self.db, '_tables'):
            self.database(cdn=cdn)
        if not name:
            name = self.memory.settings.data_model
        q = self.load_class(name, path, blanc_env, func)
        q.create_models()
        return q

    def build_request(self, environ):

        #build the request http://www.python.org/dev/peps/pep-0333/
        self.request.wsgi.version = environ.get('wsgi.version', False)
        self.request.wsgi.input = environ.get('wsgi.input', False)
        self.request.wsgi.errors = environ.get('wsgi.errors', False)
        self.request.wsgi.multithread = environ.get('wsgi.multithread', False)
        self.request.wsgi.multiprocess = environ.get('wsgi.multiprocess', \
                                                                         False)
        self.request.wsgi.run_once = environ.get('wsgi.run_once', False)
        self.request.env = self.get_headers(environ)
        #set the language Accept-Language
        try:
            self.lang = self.request.env['Accept-Language'][0:2].lower()
        except:
            self.lang = self.memory.settings.default_lang
        if self.lang == 'zh':
            #later patchen
            self.lang = 'cn'

        if self.lang not in self.memory.settings.language:
            self.lang = self.memory.settings.default_lang

        self.url = environ.get('PATH_INFO', '')
        self.is_cached = hashlib.md5(_(self.url + '_' + self.lang)).hexdigest()
        aanvraag = self.url.split('/')[1:]
        if aanvraag:
            for i, x in enumerate(aanvraag):
                self.request.args[i] = x
        if environ.get('REQUEST_METHOD', '') in ('POST', 'PUT') \
                                 and int(environ.get('CONTENT_LENGTH', False)):
            request_body_size = int(environ.get('CONTENT_LENGTH'))
            invoer = environ['wsgi.input'].read(request_body_size)
            self.post_vars = invoer
            dpost = parse_qsl(invoer)
            self.post = True
            for (k, v) in dpost:
                self.request.post[k] = v

        dget = parse_qsl(environ.get('QUERY_STRING', ''))

        if dget:
            for (key, value) in dget:
                self.request.vars[key] = value

        zout = str(self.memory.settings.cookie_salt)
        self.cookie_salt = self.encrypt(zout, algo='sha1')
        userkey = hashlib.md5()
        userkey.update(_(self.cookie_salt))
        userkey.update(_(environ.get('HTTP_USER_AGENT', False)))
        userkey.update(_(environ.get('HTTP_ACCEPT_LANGUAGE', False)))
        userkey.update(_(environ.get('REMOTE_ADDR', False)))
        #the user key
        authkey = userkey.hexdigest()
        self.cookie = authkey[0:16]
        self.cookie_value = self.encrypt(self.cookie_salt \
                                         + authkey[16:32])
        sl = str(self.cookie + '=' + self.cookie_value)

        admin = self.encrypt(authkey, algo='sha1')
        self.admin_cookie = admin[0:16]
        self.admin_cookie_value = self.encrypt(self.cookie_salt + admin)
        asl = str(self.admin_cookie + '=' + self.admin_cookie_value)
        #now lets find out if there's a session active, instead of .pop
        if [k for k in [sl] if k in self.request.env.get('Cookie', [])]:
            self.loggedin = self.cookie
        elif [k for k in [asl] if k in self.request.env.get('Cookie', [])]:
            self.isadmin = self.admin_cookie
            self.loggedin = self.cookie
        else:
            self.loggedin = False

    def user(self):
        user = self.model('jexjex_auth')
        return user.get_user()

    def serve(self):
        """
        Serves the request

        """
        if not self.post and self.memory.cache[self.is_cached]:
            return self.memory.cache[self.is_cached]
        elif self.url.startswith('/' + self.memory.settings.dbmedia_folder\
                                                                        + '/'):
            return self.download()
        else:
            return self.create_page()

    def serve_file(self, req, folder=False):
        return serve_file(folder + '/' + req)

    def download(self):
        file = self.model('cdn_model')
        data = file.serve_file()
        if data:
            return [self.status, self.headers, data]
        else:
            return self.forbidden()

    def forbidden(self):
        self.status = '403 forbidden'
        output = serve_file(self.memory.folder \
                              + '/' + self.memory.appfolder + '/http/403.html')
        return output

    def render_view(self, view='404.html', getfile=False):
        """
        In production we are caching views

        """
        if self.memory.view[str(getfile) + view] and \
                              self.memory.settings.development == 'production':
            html = self.memory.view[str(getfile) + view]
        else:
            if not getfile:
                getfile = self.memory.folder + '/' + self.memory.appfolder \
                                                        + '/views/' + str(view)
            else:
                getfile = getfile + '/views/' + str(view)
            html = serve_file(getfile)
            if self.memory.settings.development == 'production':
                    self.memory.view[str(getfile) + view] = html
        return html

    def template_parser(self, pagina, path):
        return TemplateParser(pagina, path)

    def wiew(self, view, items=False):
        return self.view(view, items)

    def view(self, view, *args):
        """
        The views

        """
        #de view
        if not 'getfile' in args:
            getfile = False
        pagina = self.render_view(view=view, getfile=getfile)
        #parse the template
        if not 'path' in args:
            path = self.memory.folder + '/' + self.memory.appfolder + '/views/'
        parser = TemplateParser(pagina, path=path)
        #render the template, added with some functionality
        if not args:
            args = dict
        env = self.environment()
        data = parser.render(env)
        #commit!
        BaseAdapter.close_all_instances('commit')
        return data

    def alt_view(self, pagina, xpath, *kwargs):
        parser = self.template_parser(pagina, path=xpath)
        data = parser.render(self.environment(), *kwargs)
        return self.commit(data)

    def commit(self, data):
        BaseAdapter.close_all_instances('commit')
        return data

    def load_class(self, module, path='controllers', blanc_env=False, \
                                                                   func=False):
        """
        Import and loads files, classes

        """
        if not blanc_env:
            blanc_env = dict()
        ophalen = self.memory.folder + '/' + self.memory.appfolder \
                                            + '/' + path + '/' + module + '.py'
        exec(serve_file(ophalen), blanc_env)
        if not func and module.title() in blanc_env:
            q = blanc_env[module.title()]
            return q(self)
        else:
            return blanc_env

    def controller(self, module=False):
        """
        Controller, returns the request handled by class or function

        """

        if not module:
            #get the first request
            module = self.memory.settings.modules[self.request.args[0]]
        q = self.load_class(module, blanc_env=self.environment())
        if hasattr(q, module.title()) or hasattr(q, '_run'):
            #run as class
            return q._run()
        else:
            #run as function
            segment = 1 if self.request.arg(0) == module else 0
            function = self.request.arg(segment) or 'index'
            functie = function.split('.')[0]
            #stripout function
            if functie in q:
                return q[functie]()
            else:
                #huf?
                try:
                    return q['index']()
                except:
                    return traceback.format_exc()

    def environment(self):
        #this will set functions and decorators
        return dict(request=self.request, T=self.T, jexjex=self, db=self.db,
                    time=self.time, date=self.date, view=self.wiew,
                    meuk=self.meuk,
                    model=self.model, encrypt=self.encrypt, old_ie=self.old_ie
                    )

    def meuk(self, fn):
        def wrapped():
            return '<h1>' + fn() + '</h1>'
        return wrapped

    def meukx(self, fn):
        def wrapped():
            return '<h2>' + fn() + '</h2>'
        return wrapped

    def set_session(self, date=19500):
        exprires = cookiedate(date)
        return exprires

    def delete_cookie(self, duur=-95000):
        self.status = '307 Temporary Redirect'
        if self.isadmin:
            waard = self.admin_cookie + ' = 1;' + self.cookie + \
               ' = 1 ;Path = /; Expires =' + self.set_session(duur) + ';'
        else:
            duur = str(self.set_session(duur))
            waard = self.cookie + ' = 1; Path = /; Expires =' + duur + ';'
        self.headers = [('Content-type', 'text/html'),
                            ('Set-Cookie', str(waard))]

    def set_cookie(self, userlevel=1, duur=19500):
        if userlevel < 100:
            waard = self.cookie + '=' + self.cookie_value + '; Path = /;'
        else:
            waard = self.admin_cookie + '=' + self.admin_cookie_value\
                                + '; Path = /; Expires =' \
                                + self.set_session(duur) + ';'

        self.headers = [('Content-type', 'text/html'),
                                 ('Set-Cookie', str(waard))]

    def create_page(self):
      #on the backend?, we will need a session
        if self.request.arg(0) == self.memory.secure:
            dmn = self.controller(self.memory.settings.secure_controller)
            return [self.status,  self.headers, dmn]
        elif self.request.arg(0) in self.memory.settings.modules:
            data = self.controller()
            return [self.status, self.headers, data]
        else:
            #run the default application
            uitvoer = self.controller(self.memory.settings.default_application)
            #adjust some headers
            return [self.status, self.headers, uitvoer]

    def create_password(self, email=False, password=False):
        hashed = hashlib.sha1(str(self.memory.settings.salt)).hexdigest()
        key = hashlib.new(self.memory.settings.algorithm)
        key.update(hashed)
        key.update(hashlib.md5(str(hashed + email)).hexdigest())
        key.update(hashlib.sha1(str(hashed + password)).hexdigest())
        word = hashlib.md5(key.hexdigest()).hexdigest()
        return word

    def send_email(self, email=False, subject=False, message=False, tls=True):
        if email and subject and message:
        #build the string
            if not hasattr(self.mail, 'send'):
                self.mail = Mail(server=str(self.memory.settings.mailserver), \
                                 sender=str(self.memory.settings.mailsender), \
                                 login=str(self.memory.settings.maillogin), \
                                 tls=tls)
        return self.mail.send(email, subject, message)

    def create_ticket(self, ticket=None, data=None):
        ticket = self.model('jexjex_tickets')
        ticket.add_ticket(refer=ticket, message=data)

    def translate(self, woord, waarden=False):
        """
        Translates strings if translation is found in memory
        """
        if self.lang == self.memory.settings.default_lang:
            return echo(woord, waarden)
        elif woord and self.memory.language[self.lang]:
            try:
                find = self.memory.language[self.lang][hash(woord)]
                if find:
                    return echo(find.encode('utf8', 'xmlcharrefreplace'), \
                                                                       waarden)
                else:
                    return echo(woord, waarden)
            except:
                return echo(woord, waarden)
        else:
            #is there a sh
            return echo(woord, waarden)

    def cache(self, name=None, data=False):
        if name == None:
            name = self.is_cached
        if data:
            self.memory.cache[name] = [self.status, self.headers, data]
        else:
            return self.memory.cache[name]

    def encrypt(self, text, algo='md5', get='hexdigest'):
        key = hashlib.new(algo)
        key.update(_(text))
        if get == 'hexdigest':
            return key.hexdigest()
        else:
            return key

    def redirect(self, location='/'):
        self.status = '307 Temporary Redirect'
        self.headers = [('Content-type', 'text/html'),
                        ('Location', location)]
        return 'redirect'

    def evil(self, waarde):
        return literal_evil(waarde)

    """
    Form, crud helpers

    """


    def validate(self, wat, waarde):
        return vorm_validate(wat, waarde)

    def vorm(self, table, id=0):
        return Vorm(table, id)

    """
    HTML helpers

    """

    def old_ie(self):
        """
        Very ugly but effective.
        Why, dear magical pixie, why!?

        """
        if self.request.env['User-Agent'].find('MSIE 7.0') > 5:
            return '7'
        elif self.request.env['User-Agent'].find('MSIE 8.0') > 5:
            return '8'
        elif self.request.env['User-Agent'].find('MSIE 6.0') > 5:
            return '6'
        else:
            return False

    def xhtml(self, reqstring='body,html,div,span,a,ul,li,p,h1,h2,h3,h4'):
        """
        XHTML generator, generates html tags

        """
        for name in reqstring.split(','):
            if not self.html[name]:
                self.html[name] = tag[name]
        return self.html

    def class_active(self, home, items=False):
        if items:
            if self.request.arg(0) not in items:
                return ' class="active"'
            else:
                return ''
        else:
            if self.request.arg(0) == home:
                return ' class="active"'
            else:
                return ''

    def html_lang(self):
        #the languae ISO 639-1
        if self.lang in self.memory.settings.language:
            if self.lang == 'cn':
                return str('zh-CN')
            else:
                return str(self.lang)
        else:
            return str(self.memory.settings.default_lang)

    def javascript(self, code=None, include=None):
        """
        javascript
        ads requested javascript to the page
        """
        e = ''
        e2 = ''
        html = self.xhtml('script')
        if code == 'show':
            for script in self.javascript_file:
                if script.startswith('js'):
                    script = '/' + self.memory.settings.media_folder + '/'\
 + script
                e += html.scripr(_type="text/javascript", _src=str(script))
            if self.javascript_inc:
                for inc in self.javascript_inc:
                    e2 += inc + '\n'
                e += html.script(e2, _type="text/javascript")
            return e
        elif include:
            if include not in self.javascript_file:
                self.javascript_file.append(include)
        else:
            if include not in self.javascript_inc:
                self.javascript_inc.append(code)

    def css(self, code=None, include=None):
        """
        css
        ads requested javascript to the page
        """
        e = ''
        e2 = ''
        html = self.xhtml('link, style')
        if code == 'show':
            for script in self.css_file:
                if script.startswith('css'):
                    script = '/' + self.memory.settings.media_folder + '/'\
                                                                       + script
                e += html.link(_href=str(script), _rel='stylesheet')
            if self.css_inc:
                for inc in self.css_inc:
                    e2 += inc + '\n'
                e += html.style(e2, _type="text/css")
            return e
        elif include:
            if include not in self.css_file:
                self.css_file.append(include)
        else:
            if include not in self.css_inc:
                self.css_inc.append(code)

    """
    Fetch

    """

    def fetch(self, url):
        return fetch_url(url)

    """
    Date and time helpers

    """

    def prettydate(self, waarde, dagen=False):
        if not self.tools:
            self.tools = Tools(self)
        return self.tools.prettydate(waarde, dagen)

    def delta(self, days=False, hours=False, minutes=False):
        """
        timedelta
        """
        return datetime.timedelta(days, hours, minutes)

    def datetime(self):
        return datetime

    def timedelta(self):
        return datetime.timedelta

    def timediff(self, datum, teruggave=False, **kwargs):
        """
        get the difference between current and givven in timedelta
        """
        return self.prettydate(datum, dagen=True)

    def date(self, datum, teruggave=False):
        return self.time(datum, teruggave, date=True)

    def now(self):
        return datetime.datetime.now()

    def utcnow(self):
        return datetime.datetime.utcnow()

    def time(self, datum, teruggave=False, **kwargs):
        """
        based on the user language, rebuilds the datetime object
        completly disregarding utc or datetime.now
        """
        wtime = 0
        timestring = False
        #localtime = self.memory.settings.server_timezone
        #datestring = self.memory.settings.server_datestring
        #defaulttime = self.memory.settings.default_timezone
        #break it appart - date
        [year, month, day, hour, seconds, millisec] = timeparts(datum)
        if self.memory.language[self.lang]:
            try:
                timestring = self.memory.language[self.lang][hash('_timestr')]
                datestring = self.memory.language[self.lang][hash('_datestr')]
                try:
                    wtime = int(self.memory.language[self.lang][hash('_diff')])
                except:
                    wtime = 0
            except:
                timestring = False
                datestring = False
                wtime = 0
        if 'date' in kwargs:
            tstr = datestring or self.memory.settings.server_datestring
        else:
            tstr = timestring or self.memory.settings.server_timestring

        server = datetime.datetime(year, month, day, hour, seconds, millisec)
        #need to adjust the time
        tijd = server + datetime.timedelta(minutes=wtime)

        if teruggave:
            return tijd
        else:
            #return the string
            #set the time
            [year, month, day, hour, seconds, millisec] = timeparts(tijd)
            if hour < 10:
                hour = str('0' + str(hour))
            if seconds < 10:
                seconds = str('0' + str(seconds))
            return echo(tstr, [year, month, day, hour, seconds, millisec])


class jexjex_server(simple_server.WSGIServer):
    # To increase the backlog
    request_queue_size = 500


class jexjex_handler(simple_server.WSGIRequestHandler):
    # to disable logging
    def log_message(self, *args):
        pass


def server(environ, start_response):
    app = ''
    eget = environ.get
    if not eget('PATH_INFO', None) and eget('REQUEST_URI', None):
        items = environ['REQUEST_URI'].split('?')
        environ['PATH_INFO'] = items[0]
        if len(items) > 1:
            environ['QUERY_STRING'] = items[1]
    #some vars
    uri = environ['PATH_INFO']
    ext = extension(uri)
    response_headers = False
    status = '200 ok'
    output = ' '

    """
     block some bogus request
    """
    if [k for k in memory.settings.blacklist if k in uri.lower()]:
        status = '403 forbidden'
        output = serve_file(memory.folder + '/' + memory.appfolder \
                                                      + '/views/http/403.html')
        start_response(status, [('Content-type', 'text/html'),
                                        ('Content-Length', str(len(output)))])
        return output
    else:
        try:
            if uri.lower() in ['/favicon.ico', '/robots.txt', '/humans.txt']:
                output = serve_file(memory.folder + '/' + 'static' + uri)

            elif uri.startswith('/' + memory.settings.media_folder + '/'):
                bst = uri.replace('/' + memory.settings.media_folder + '/', '')
                output = serve_file(memory.folder + '/static/' + str(bst))

            else:
                app = Jexjex(environ, memory)
                status, response_headers, output = app.serve()
                del app
        except:
            if memory.settings.log:
                try:
                    fout = traceback.format_exc()
                    output = fout
                    #output = '404'
                    #if app:
                    #    if not hasattr(app, 'create_ticket'):
                    #        app = Jexjex(environ, memory)
                    #app.create_ticket(ticket=app.encrypt(str(fout)),\
                    #              data=output)
                except:
                    output = traceback.format_exc()
            else:
                #testing
                output = traceback.format_exc()
    """
    if a request returns a simple 404 string we'll show an error page
    or

    """
    if output == '404':
        status = '404 not found'
        ext = 'text/html'
        output = serve_file(memory.folder + '/' + memory.appfolder \
                                                      + '/views/http/404.html')
    elif output == 'redirect':
        output = serve_file(memory.folder + '/' + memory.appfolder \
                                                      + '/views/http/307.html')

    if not response_headers:
        req = ext.split('/')
        if [k for k in ['image', 'css', 'javascript'] if k in req]:
            response_headers = [('Content-type', ext),
            ('Cache-Control', 'public, max-age=290304000'),
                                     ('Content-Length', str(len(str(output))))]
        else:
            response_headers = [('Content-type', ext),
                                     ('Content-Length', str(len(str(output))))]

    start_response(status, response_headers)

    return [_(output)]


def _(s, enc='utf8', err='strict'):
    """
    Wegschrijven is Dutch for writeaway, the bytes part in it is quit obvious.
    Makes sure we've got bytes

    """
    uitvoer = str(s)
    return bytes(uitvoer.encode(enc, err))


def get_folder():
    p = __file__.split('jexjex_server')
    folder = os.path.abspath(p[0])
    sys.path.append(folder)
    return folder

memory = Memory()
memory.folder = get_folder()
memory.config(serve_file(memory.folder + '/config.jexjex'))
#ad import path
sys.path.append(memory.folder + '/' + memory.appfolder)
#and another, the modules
sys.path.append(memory.folder + '/' + memory.appfolder + '/modules')


def start_server(port=memory.settings.port, hostname=memory.settings.hostname):
    pid = os.getpid()
    echo("Jexjex - v{0} - {1}", [memory.settings.version,\
                                           memory.settings.release], ret=False)
    echo("A fast,stable,secure and minimalistic framework", ret=False)
    echo("Copyright Jan-Karel Visser - all rights are reserved", ret=False)
    echo("Licensed under the LGPL v3", ret=False)
    echo("Serving on port {0}...", [port], ret=False)
    echo('use "kill -SIGTERM {0}" or ^C to shutdown Jexjex or panic', \
                                                              [pid], ret=False)
    httpd = jexjex_server((hostname, port), jexjex_handler)
    httpd.set_app(server)
    httpd.serve_forever()

if __name__ == '__main__':
    start_server()
